package com.inspur.edp.common.expr.visitor;

import com.inspur.edp.common.expr.ast.CompileUnitParser;
import com.inspur.edp.common.expr.exception.ExpressException;
import com.inspur.edp.common.expr.parser.ExpressAstParser;

import java.util.HashMap;
import java.util.Map;

/**
 * @author lizhaorui
 * @date 2025/8/18
 * @description
 */
public class ExpressVisitManager {

    private static ExpressVisitManager instance;

    private Map<Class, ExpressVisitor> visitMap = new HashMap<>();

    public static ExpressVisitManager getInstance() {
        if (instance == null) {
            synchronized (ExpressVisitManager.class) {
                if (instance == null) {
                    ExpressVisitManager temp = new ExpressVisitManager();
                    temp.visitMap.put(CompileUnitParser.NumberValExprContext.class, new NumberValExprVisitor());
                    temp.visitMap.put(CompileUnitParser.StringValExprContext.class, new StringValExprVisitor());
                    temp.visitMap.put(CompileUnitParser.BooleanValExprContext.class, new BooleanValExprVisitor());
                    temp.visitMap.put(CompileUnitParser.ThisExprContext.class, new ThisExprVisitor());
                    temp.visitMap.put(CompileUnitParser.NullValExprContext.class, new NullValExprVisitor());
                    temp.visitMap.put(CompileUnitParser.NotExprContext.class, new NotExprVisitor());
                    temp.visitMap.put(CompileUnitParser.NewExprContext.class, new NewExprVisitor());
                    temp.visitMap.put(CompileUnitParser.VarDeclarationExprContext.class, new VarDeclarationExprVisitor());
                    temp.visitMap.put(CompileUnitParser.SimpleNameExprContext.class, new SimpleNameExprVisitor());
                    temp.visitMap.put(CompileUnitParser.PpmmPreExprContext.class, new PpmmPreExprVisitor());
                    temp.visitMap.put(CompileUnitParser.FieldAccessExprContext.class, new FieldAccessExprVisitor());
                    temp.visitMap.put(CompileUnitParser.PlusMinusPostExprContext.class, new PlusMinusPostExprVisitor());
                    temp.visitMap.put(CompileUnitParser.ArrayAccessExprContext.class, new ArrayAccessExprVisitor());
                    temp.visitMap.put(CompileUnitParser.MethodInvokeExprContext.class, new MethodInvokeExprVisitor());
                    temp.visitMap.put(CompileUnitParser.MultiplyDivideExprContext.class, new MultiplyDivideExprVisitor());
                    temp.visitMap.put(CompileUnitParser.PlusMinusExprContext.class, new PlusMinusExprVisitor());
                    temp.visitMap.put(CompileUnitParser.CompareExprContext.class, new CompareExprVisitor());
                    temp.visitMap.put(CompileUnitParser.TypeCastExprContext.class, new TypeCastExpressVisitor());
                    temp.visitMap.put(CompileUnitParser.AssignValExprContext.class, new AssignValExprVisitor());
                    temp.visitMap.put(CompileUnitParser.AndOrExprContext.class, new AndOrExprVisitor());
                    temp.visitMap.put(CompileUnitParser.AnonmousFuncExprContext.class, new AnonymousFuncExprVisitor());
                    temp.visitMap.put(CompileUnitParser.EnclosureExprContext.class, new EnclosureExprVisitor());
                    temp.visitMap.put(CompileUnitParser.ObjectValueExprContext.class, new ObjectValueExprVisitor());
                    temp.visitMap.put(CompileUnitParser.ArrayValueExprContext.class, new ArrayValueExprVisitor());
                    temp.visitMap.put(CompileUnitParser.SimplifyMethodInvokeExprContext.class, new SimplifyMethodInvokeExprVisitor());
                    temp.visitMap.put(CompileUnitParser.UnaryMinusExprContext.class, new UnaryMinusExprVisitor());
                    instance = temp;
                }
            }
        }
        return instance;
    }

    public static Object visit(JavaVisitor javaVisitor, CompileUnitParser.ExpressContext ctx) {
        ExpressAstParser.initType(ctx, javaVisitor);
        return getVisitor(ctx).visit(ctx, javaVisitor);
    }

    public static ExpressVisitor getVisitor(CompileUnitParser.ExpressContext ctx) {
        ExpressVisitManager manager = ExpressVisitManager.getInstance();
        Class cls = ctx.getClass();
        if (manager.visitMap.containsKey(cls)) {
            return manager.visitMap.get(cls);
        } else {
            throw new ExpressException("not support primitive type " + cls.getName());
        }
    }

    public interface ExpressVisitor {
        Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor);
    }

    static class NumberValExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitNumberValExpr((CompileUnitParser.NumberValExprContext) ctx);
        }

    }

    static class StringValExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitStringValExpr((CompileUnitParser.StringValExprContext) ctx);
        }
    }

    static class BooleanValExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitBooleanValExpr((CompileUnitParser.BooleanValExprContext) ctx);
        }
    }

    static class ThisExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitThisExpr((CompileUnitParser.ThisExprContext) ctx);
        }
    }

    static class NullValExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitNullValExpr((CompileUnitParser.NullValExprContext) ctx);
        }
    }

    static class NotExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitNotExpr((CompileUnitParser.NotExprContext) ctx);
        }
    }

    static class NewExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitNewExpr((CompileUnitParser.NewExprContext) ctx);
        }
    }

    static class VarDeclarationExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitVarDeclarationExpr((CompileUnitParser.VarDeclarationExprContext) ctx);
        }
    }

    static class SimpleNameExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitContext) {
            return visitContext.visitSimpleNameExpr((CompileUnitParser.SimpleNameExprContext) ctx);
        }

    }

    static class PpmmPreExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitPpmmPreExpr((CompileUnitParser.PpmmPreExprContext) ctx);
        }
    }

    static class FieldAccessExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitFieldAccessExpr((CompileUnitParser.FieldAccessExprContext) ctx);
        }

    }

    static class PlusMinusPostExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitPlusMinusPostExpr((CompileUnitParser.PlusMinusPostExprContext) ctx);
        }
    }

    static class ArrayAccessExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitArrayAccessExpr((CompileUnitParser.ArrayAccessExprContext) ctx);
        }
    }

    static class MethodInvokeExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitMethodInvokeExpr((CompileUnitParser.MethodInvokeExprContext) ctx);
        }
    }

    static class MultiplyDivideExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitMultiplyDivideExpr((CompileUnitParser.MultiplyDivideExprContext) ctx);
        }
    }

    static class PlusMinusExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitPlusMinusExpr((CompileUnitParser.PlusMinusExprContext) ctx);
        }
    }

    static class CompareExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitCompareExpr((CompileUnitParser.CompareExprContext) ctx);
        }
    }

    static class TypeCastExpressVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitTypeCastExpr((CompileUnitParser.TypeCastExprContext) ctx);
        }
    }

    static class AssignValExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitAssignValExpr((CompileUnitParser.AssignValExprContext) ctx);
        }
    }

    static class AndOrExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitAndOrExpr((CompileUnitParser.AndOrExprContext) ctx);
        }

    }

    static class UnaryMinusExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitUnaryMinusExpr((CompileUnitParser.UnaryMinusExprContext) ctx);
        }

    }

    static class EnclosureExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitEnclosureExpr((CompileUnitParser.EnclosureExprContext) ctx);
        }
    }

    static class ObjectValueExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitObjectValueExpr((CompileUnitParser.ObjectValueExprContext) ctx);
        }

    }

    static class ArrayValueExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitArrayValueExpr((CompileUnitParser.ArrayValueExprContext) ctx);
        }

    }


    static class SimplifyMethodInvokeExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitSimplifyMethodInvokeExpr((CompileUnitParser.SimplifyMethodInvokeExprContext) ctx);
        }

    }

    static class AnonymousFuncExprVisitor implements ExpressVisitor {

        @Override
        public Object visit(CompileUnitParser.ExpressContext ctx, JavaVisitor visitor) {
            return visitor.visitAnonmousFuncExpr((CompileUnitParser.AnonmousFuncExprContext) ctx);
        }
    }

}